package org.weso.lodin.appserv;

import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.weso.lodin.analyzer.CountryReconciliator;
import org.weso.lodin.dao.CountryDAO;
import org.weso.lodin.dao.RankingScoreObservationDAO;
import org.weso.lodin.generated.Dataset;
import org.weso.lodin.generated.IdIndicator;
import org.weso.lodin.to.CountryTO;
import org.weso.lodin.to.ObservationTO;
import org.weso.lodin.to.RankingScoreObservationTO;
import org.weso.lodin.utils.StatusUtils;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.vocabulary.DCTerms;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;

public class RankingScoresTransformer {
	private static final String CHANGE_RESOURCE = "Change";
	private static final String CONTROL_YEAR = "2000";
	protected static Logger logger = Logger.getLogger(RankingScoresTransformer.class);
	private static final String SCORE_TAG = "score";
	private static final String RANKING_TAG = "ranking";

	private CountryDAO daoCountries;
	int count  = 0;

	public RankingScoresTransformer(){
		
	}
	public RankingScoresTransformer(CountryDAO daoCountries){
		this.daoCountries = daoCountries;
	}
	
	public Model transform(RankingScoreObservationDAO dao, List<Dataset> datasets){
		Model model =ModelFactory.createDefaultModel();
		for(Dataset ds: datasets){
			List<RankingScoreObservationTO> observations = dao.getObservations(datasets);
			logger.info("Decorating from indicator: "+ds.getId());
			decorateCountries(daoCountries,observations);
			logger.info("Create RDF model from indicator: "+ds.getId());
			model.add(observationsAsRDF(observations,ds));			
		}
	
		return model;
	}
	private Model observationsAsRDF(
			List<RankingScoreObservationTO> observations, Dataset ds) {
		Model model =ModelFactory.createDefaultModel();
		Resource obs = model.createResource("http://purl.org/linked-data/cube#Observation");
		Resource weso = model.createResource(TransformerAppServ.ORGANIZATION_BASE_URI+"WESO");
		Resource webfoundation = model.createResource(TransformerAppServ.ORGANIZATION_BASE_URI+"webfoundation");
		Resource indicator = getResourceType(model, ds);
	
		for(RankingScoreObservationTO observation:observations){
			CountryTO countryDecorated = observation.getCountryDecorated();			
			String code = null;
			String countryName = null;
			Resource uriArea = null;
			if(countryDecorated == null){
				logger.warn("Fail country decorated value: "+countryDecorated+" with initial country "+observation.getCountry());
				code = TransformerAppServ.encodeNotCountry(observation.getCountry()); //FIXME
				countryName = code;
				uriArea = model.createResource(TransformerAppServ.REGION_BASE_URI+code);
			}else{
				code = countryDecorated.getCode();
				countryName = countryDecorated.getName();
				uriArea = model.createResource(observation.getCountryDecorated().toURI());
			}
		
			
			String title = ds.getIndicator().value()+", "+getRankingOrScore(observation);
			String uri = TransformerAppServ.RS_BASE_URI + "rs"+(count++);

			
			Resource observationRDF = model.createResource(uri);	
			model.add(observationRDF, RDF.type, obs);
			Resource status = model.createResource(TransformerAppServ.HTTP_PURL_ORG_LINKED_DATA_SDMX_2009_CODE+StatusUtils.NORMAL);	
								

			model.add(observationRDF,DCTerms.publisher,webfoundation);
			model.add(observationRDF,DCTerms.contributor,weso);
			model.add(observationRDF,DCTerms.source,observation.getDataset().getId());
			model.add(observationRDF,model.getProperty(TransformerAppServ.ONTOLOGY_BASE_URI+"ref-type"),indicator);
			double value;
			try{
				value = Double.valueOf(observation.getValue());
				model.addLiteral(observationRDF,model.getProperty(TransformerAppServ.ONTOLOGY_BASE_URI+"value"),value);
			}catch(java.lang.NumberFormatException e){
				logger.warn("Resource: "+uri+" exception converting string "+observation+" to number, set to MISSING VALUE.");
				status = model.createResource(TransformerAppServ.HTTP_PURL_ORG_LINKED_DATA_SDMX_2009_CODE+StatusUtils.MISSING);	
									
			}catch(Exception e){
				logger.warn("Resource: "+uri+" exception converting string "+observation+" to number, set to MISSING VALUE.");
				status = model.createResource(TransformerAppServ.HTTP_PURL_ORG_LINKED_DATA_SDMX_2009_CODE+StatusUtils.MISSING);	
			
			}
//			model.add(observationRDF,RDFS.comment,
//					TransformerAppServ.literalLang(model,title+" in "+
//							TransformerAppServ.prettyPrint(countryName)+" during "+observation.getYear(),
//							TransformerAppServ.LANG_EN));
			if(!observation.getYear().equalsIgnoreCase(CONTROL_YEAR)){
				model.add(observationRDF,RDFS.label,
						TransformerAppServ.literalLang(model,title+" of "+
								TransformerAppServ.prettyPrint(countryName)+" in "+observation.getYear(),
								TransformerAppServ.LANG_EN));
				model.add(observationRDF,model.getProperty(TransformerAppServ.ONTOLOGY_BASE_URI+"ref-sheet"),
						getResource(model,getRankingOrScore(observation)));
				model.addLiteral(observationRDF,DCTerms.date,Integer.valueOf(observation.getYear()));
				model.addLiteral(observationRDF,model.getProperty(
						TransformerAppServ.ONTOLOGY_BASE_URI+"ref-year"),
						Integer.valueOf(observation.getYear()));
			}else{

				model.add(observationRDF,RDFS.label,
						TransformerAppServ.literalLang(model,"Change of "+
								TransformerAppServ.prettyPrint(countryName)+" with regards to "+ds.getIndicator().value()+".",
								TransformerAppServ.LANG_EN));
				model.add(observationRDF,model.getProperty(TransformerAppServ.ONTOLOGY_BASE_URI+"ref-sheet"),
						getResource(model,CHANGE_RESOURCE));
			}
			model.add(observationRDF,model.getProperty(TransformerAppServ.HTTP_PURL_ORG_LINKED_DATA_SDMX_2009_CONCEPT+"obsStatus"),status);			
			model.add(observationRDF,model.getProperty(
					TransformerAppServ.ONTOLOGY_BASE_URI+"ref-area"),uriArea);
				
		}
		return model;
	}
	
	
	
	private Resource getResource(Model model, String rankingOrScore) {
		return model.createResource(TransformerAppServ.ONTOLOGY_BASE_URI+StringUtils.capitalize(rankingOrScore));
	}
	protected static void decorateCountries(CountryDAO daoCountries, List<RankingScoreObservationTO> observations){
		List<CountryTO> countries = daoCountries.getCountries();
		CountryReconciliator reconciliatorCountry = new CountryReconciliator(countries);	
	    for(RankingScoreObservationTO observation:observations){
	    	List<CountryTO> results = reconciliatorCountry.search(observation);
	    	if(results.size()>0){
	    		CountryTO match = results.get(0);
	    		//logger.debug("Match for country name "+observation.getCountry()+" found "+match.getName());	    		
	    		observation.setCountryDecorated(match);
	    	}else{
	    		logger.warn("No match country for observation "+observation);
	    	}	    	
	    }	    	
	  }
	protected Resource getResourceType(Model model, Dataset ds){
		IdIndicator id = ds.getIndicator();
		String baseUri = TransformerAppServ.INDICATOR_BASE_URI;
		System.out.println (id);
		if(id.equals(IdIndicator.READINESS)
				|| id.equals(IdIndicator.THE_WEB)
				|| id.equals(IdIndicator.IMPACT)){
			baseUri = TransformerAppServ.INDEX_BASE_URI;
		}
		else if(id.equals(IdIndicator.COMMUNICATIONS_INFRASTRUCTURE)
				|| id.equals(IdIndicator.INSTITUTIONAL_INFRASTRUCTURE)
				|| id.equals(IdIndicator.WEB_USAGE)
				|| id.equals(IdIndicator.WEB_CONTENT)
				|| id.equals(IdIndicator.SOCIAL)
				|| id.equals(IdIndicator.ECONOMIC)
				|| id.equals(IdIndicator.POLITICAL)				
				){
			baseUri = TransformerAppServ.COMPONENT_BASE_URI;
			
		}else if (id.equals(IdIndicator.COMPOSITE_SECONDARY_DATA)){
			baseUri = TransformerAppServ.INDEX_BASE_URI;
			return model.createResource(baseUri+"ds");
		}
		return model.createResource(baseUri+ds.getIndicator().value());
	}
	
	//FIXME: Extract
	public String getRankingOrScore(RankingScoreObservationTO to){
		String id = to.getDataset().getId();
		if (id.equals("2011-rankings_2") || 
				id.equals("Components-secondary_2") || 
				id.equals("Overall-composite-secondarydata_2") || 
				id.equals("Sub-Indexes-secondary_2")){
			return RANKING_TAG;
		}else return SCORE_TAG;
	}
}
